﻿using System;
using System.Collections.Generic;

namespace GxFramework
{
    public class ObjectPool
    {
        readonly Stack<object> _stack = new Stack<object>();
        
        Action<object> _onGet,_onRelease,_onDestroy;

        int _countAll;
        public void SetCallback(Action<object> onGet, Action<object> onRelease, Action<object> onDestroy)
        {
            _onGet = onGet;
            _onRelease = onRelease;
            _onDestroy = onDestroy;
        }
        public int countAll { get { return _countAll; } }
        public int countActive { get { return countAll - countInactive; } }
        public int countInactive { get { return _stack.Count; } }
        public object Get()
        {
            object item = default(object);
            bool hasCreate = true;
            if (_stack.Count != 0)
            {
                item = _stack.Pop();
                if (hasCreate && null != _onGet)
                    _onGet(item);
            }
            
            return item;
        }
        internal void OnSpawn(object item)
        {
            ++_countAll;
        }
        public void Put(object item)
        {
            if (_stack.Count > 0 && ReferenceEquals(_stack.Peek(), item))
                throw new Exception("[ObjectPool] Internal error. Trying to put object that is already released to pool.");
            _stack.Push(item);
            ++ _countAll;
        }
        public void Release(object item)
        {
            if (_stack.Count > 0 && ReferenceEquals(_stack.Peek(), item))
                throw new Exception("[ObjectPool] Internal error. Trying to release object that is already released to pool.");
            if (null != _onRelease)
                _onRelease(item);
            _stack.Push(item);
        }
        public void Clear()
        {
            if (null == _onDestroy)
            {
                _countAll -= _stack.Count;
                _stack.Clear();
                return;
            }
            while (_stack.Count != 0)
            {
                -- _countAll;
                _onDestroy(_stack.Pop());
            }
        }
        public void Clear(int reserveCount)
        {
            while (_stack.Count > reserveCount)
            {
                --_countAll;
                var item = _stack.Pop();
                _onDestroy(item);
            }
        }
    }
}
